﻿using GylCSharpUtils.Common.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TaiwuModFramework.Common.Abstract;
using TaiwuModFramework.Common.Info;
using TaiwuModFramework.Common.Manager;
using TaiwuModFramework.Common.Utils;
using static TaiwuModFramework.Common.Info.ReqInfo;

namespace TaiwuModFramework.Common.Base {
    public class BaseReqClient : AReqClient {

        private AMsgClient client0;
        private AMsgClient MsgClient { get { return AFwDomain.MsgClient; } }
        private ALogger Log { get { return AFwDomain.Log; } }
        private Dictionary<long, ReqInfoPackage> ReqCache = new Dictionary<long, ReqInfoPackage>();

        public BaseReqClient() {
            CheckMsgClient();  
        }


        public override ReqBuilder Req(string modIdStr, string reqPath) {
            return new ReqBuilder(this, modIdStr, reqPath);
        }


        public override object Send(ReqInfo req) {
            return Send(req, out _);
        }
        public override object Send(ReqInfo req, out RespInfo resp) {
            CheckMsgClient();
            resp = null;
            CreateTempObj(req, null, out ReqInfoPackage package, out MsgInfo msg);
            if(package.req.IsNotify) {
                MsgClient.Send(msg);
                Log.Info("发送通知");
                return null;
            }
            ReqCache.Add(package.ticks, package);
            MsgClient.Send(msg);
            Log.Info("发送请求");
            package.waitEvent.WaitOne();
            resp = package.resp;
            return resp.data;
        }
        public override void SendAsync(ReqInfo req, Action<RespInfo> respHandler) {
            CheckMsgClient();
            if(req.IsNotify) {
                var ticks = TimeUtils.GetNowTicks();
                MsgClient.Send(new MsgInfo(ticks, 0, ticks, req));
                Log.Info("发送通知");
                return;
            }
            CreateTempObj(req, respHandler, out ReqInfoPackage package, out MsgInfo msg);
            ReqCache.Add(package.ticks, package);
            MsgClient.Send(msg);
            Log.Info("发送请求");
        }


        private void CreateTempObj(ReqInfo req, Action<RespInfo> respHandler ,out ReqInfoPackage package, out MsgInfo msg) {
            package = new ReqInfoPackage();
            package.req = req;
            if(respHandler == null) {
                package.waitEvent = new ManualResetEvent(false);
            } else {
                package.respHendler = respHandler;
            }
            long ticks = TimeUtils.GetNowTicks();
            package.ticks = ticks;
            msg = new MsgInfo(ticks, 0, ticks, req);
        }

        private void CheckMsgClient() {
            if(MsgClient == null) throw new Exception("未配置MsgClient");
            if(MsgClient == client0) return;
            client0 = MsgClient;
            MsgClient.SetConsumer(ProcessMsg);
            Log.Info("配置Consumer");
        }


        private void ProcessMsg(MsgInfo msg) {
            object data = msg.data;
            if(typeof(ReqInfo).Equals(data.GetType())){
                ProcessReq((ReqInfo)data, msg);
            }else if(typeof(RespInfo).Equals(data.GetType())) {
                ProcessResp((RespInfo)data, msg);
            }

        }

        private void ProcessReq(ReqInfo req, MsgInfo msg) {
            try {
                Log.Info("收到请求");
                var result = ServiceManager.CallService(req.ModIdStr, req.ServiceName, req.ArgTypeNames, req.Args);
                if(req.IsNotify) return;
                MsgClient.Send(new MsgInfo(msg.mId, (sbyte)(msg.mIndex + 1), TimeUtils.GetNowTicks(), RespInfo.Success(result))); // 发送响应
            } catch(Exception e) {
                Log.Error(e);
                // 发送错误响应
                MsgClient.Send(new MsgInfo(msg.mId, (sbyte)(msg.mIndex + 1), TimeUtils.GetNowTicks(), RespInfo.Error(e.ToString()))); // 发送响应
            }
            

            
        }
        private void ProcessResp(RespInfo resp, MsgInfo msg) {
            try {
                Log.Info("收到响应");
                ReqCache.TryGetValue(msg.mId, out ReqInfoPackage package);
                if(package == null) return;
                package.resp = resp;
                if(package.respHendler != null) package.respHendler(resp);
                if(package.waitEvent != null) package.waitEvent.Set();
            }catch(Exception e) {
                Log.Error(e);
            } finally {
                ReqCache.Remove(msg.mId);
            }
            
        }
        
    }
}
